#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "host_framework.h"

void cl_plugin_init() {}

const char* cl_plugin_get_source_name() { return "add_number.cl"; }

const char* cl_plugin_get_kernel_name() { return "add_number"; }

int cl_plugin_do_work(cl_host_ctx_t* ctx) {
    fprintf(stderr, "Add_number do_work\n");
    cl_int i, j, err;
    size_t local_size, global_size;
#define ARRAY_SIZE 64
    /* Data and buffers */
    float data[ARRAY_SIZE];
    float sum[2], total, actual_sum;
    cl_mem input_buffer, sum_buffer;
    cl_int num_groups;
   /* Initialize data */
   for(i=0; i<ARRAY_SIZE; i++) {
      data[i] = 1.0f*i;
   }

    /* Create data buffer */
    global_size = 8;
    local_size = 4;
    num_groups = global_size / local_size;
    input_buffer = clCreateBuffer(ctx->platform.context,
                                  CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
                                  ARRAY_SIZE * sizeof(float), data, &err);
    sum_buffer = clCreateBuffer(ctx->platform.context,
                                CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
                                num_groups * sizeof(float), sum, &err);
    if (err < 0) {
        perror("Couldn't create a buffer");
        exit(1);
    };

    /* Create kernel arguments */
    err = clSetKernelArg(ctx->kernel, 0, sizeof(cl_mem), &input_buffer);
    err |= clSetKernelArg(ctx->kernel, 1, local_size * sizeof(float), NULL);
    err |= clSetKernelArg(ctx->kernel, 2, sizeof(cl_mem), &sum_buffer);
    if (err < 0) {
        perror("Couldn't create a kernel argument");
        exit(1);
    }

    /* Enqueue kernel */
    err = clEnqueueNDRangeKernel(ctx->cmd_queue, ctx->kernel, 1, NULL,
                                 &global_size, &local_size, 0, NULL, NULL);
    if (err < 0) {
        perror("Couldn't enqueue the kernel");
        exit(1);
    }

    /* Read the kernel's output */
    err = clEnqueueReadBuffer(ctx->cmd_queue, sum_buffer, CL_TRUE, 0,
                              sizeof(sum), sum, 0, NULL, NULL);
    if (err < 0) {
        perror("Couldn't read the buffer");
        exit(1);
    }

    /* Check result */
    total = 0.0f;
    for (j = 0; j < num_groups; j++) {
        total += sum[j];
    }
    actual_sum = 1.0f * ARRAY_SIZE / 2 * (ARRAY_SIZE - 1);
    printf("Computed sum = %.1f.\n", total);
    if (fabs(total - actual_sum) > 0.01 * fabs(actual_sum))
        printf("Check failed.\n");
    else
        printf("Check passed.\n");

    return 0;
}

void cl_plugin_deinit() {}
